package com.sunriz.motordrive.server.photoThermal.Impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sunriz.motordrive.domain.DTO.DriverConfigDTO;
import com.sunriz.motordrive.domain.DTO.MotorParamDTO;
import com.sunriz.motordrive.domain.DTO.Result;
import com.sunriz.motordrive.domain.DTO.SetValueDTO;
import com.sunriz.motordrive.exception.MotorException;
import com.sunriz.motordrive.server.common.SetValueServer;
import com.sunriz.motordrive.server.photoThermal.MotorParamServer;
import com.sunriz.motordrive.server.common.impl.BaseSerialImpl;
import com.sunriz.motordrive.utils.ArrayUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;

/**
 * ClassName: TimedQueryImpl
 * Package: com.sunriz.motordrive.server.impl
 * Description:
 *
 * @Author BuTang
 * @Create 2024/4/24 10:24
 * @Version 1.0
 */

@Service
@Slf4j
public class MotorParamServerImpl implements MotorParamServer {

    @Autowired
    BaseSerialImpl serialPortImpl;
    @Autowired
    SetValueServer setValueServer;

    public static Map<Integer, Integer> mapOnlyRead = new HashMap<>();
    public static Map<Integer, Integer> mapReadAndWrite = new HashMap<>();


    public static ArrayList byte32 = new ArrayList();

    private Map<Integer, Integer> selectMap = new HashMap();
    private ArrayList list32 = new ArrayList();

    /**
     * 存储json文件读取的数据
     */
    private List<DriverConfigDTO> list;


    /**
     * 如果没
     */
    private String NO_DATA_AVAILABLE = "未查询到数据";
    private static Map resultAllData = new HashMap();


    {
        // 进行查询参数的配置（读取json文件）
        this.init();
    }


    /**
     * 传输只读数据
     *
     * @return 使用modbus传输数据，后上报到前端
     */
    @Override
    public Result getOnlyReadData() {
        jssc.SerialPort myPort = BaseSerialImpl.serialPort;

        // 判断端口是否开启，若开启，则开始定时查询数据
        if (myPort != null) {

            System.out.println(mapOnlyRead.values().size());
            if (myPort.isOpened()) {
                mapOnlyRead.forEach((integer, integer2) -> {
                    serialPortImpl.sendModbus(ArrayUtils.fillIn0304Msg(1, 4, integer, integer2));
                });
            }
        } else {
            log.info("端口尚未开启，无法读取数据");
        }
        return Result.success(BaseSerialImpl.returnRead);
    }


    @Override
    public Result getReadAndWrite() {
        jssc.SerialPort myPort = BaseSerialImpl.serialPort;
        // 判断端口是否开启，若开启，则开始定时查询数据
        if (myPort != null) {
            if (myPort.isOpened()) {
                mapReadAndWrite.forEach((integer, integer2) -> {
                    serialPortImpl.sendModbus(ArrayUtils.fillIn0304Msg(1, 3, integer, integer2));
                });
            }
        } else {
            log.info("端口尚未开启，无法读取数据");
        }
        return Result.success(BaseSerialImpl.returnReadAndWrite);
    }


    @Override
    public Result getData(String slaveId) {
        jssc.SerialPort myPort = BaseSerialImpl.serialPort;
        // 将三十二位的寄存器赋值到BaseSerialPortImpl中
        BaseSerialImpl.list32 = list32;

        // 判断端口是否开启，若开启，则开始定时查询数据
        if (myPort != null) {
            if (myPort.isOpened()) {
                selectMap.forEach((integer, integer2) -> {
                    serialPortImpl.sendModbus(ArrayUtils.fillIn0304Msg(Integer.parseInt(slaveId), 3, integer, integer2));
                });
            }
        } else {
            log.info("端口尚未开启，无法读取数据");
        }

        List<DriverConfigDTO> driverConfigDTOS = this.handleData();
//        resultAllData = BaseSerialPortImpl.resultAllData;



        return Result.success(driverConfigDTOS);
    }

    /**
     * 驱动数值的下发
     * @param setValueDTO 包含 address 和 value
     */
    @Override
    public void setValue(SetValueDTO setValueDTO) {
        String address = setValueDTO.getAddress();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getAddress().equals(address)) {
                String accessMode = list.get(i).getAccessMode();
                if (accessMode.equals("只读")){
                    // 如果是只读数据，则直接抛出异常，交给全局异常处理器处理
                    throw new MotorException("该寄存器是只读寄存器，无法进行数据下发");
                }else {
                    String type = list.get(i).type;
                    if (type.equals("float")){
                        // 如果是float类型，那么需要进行数值转换后再进行下发
                        setValueServer.sendFloat(setValueDTO.getSlaveId(),address, setValueDTO.value);
                    }else {
                        // int类型直接下发
                        setValueServer.single(setValueDTO);
                    }
                    // 发送完成后，直接退出for循环
                    break;
                }
            }
        }
    }


    private void init() {
        // 初始化
        Integer startAddress = 1;
        Integer length = -1;
        Integer previousAddress = -1;
        Integer previousLength = -1;

        // 获取配置信息
        ObjectMapper mapper = new ObjectMapper();
        File file = new File("./json/driver/config.json");
        try {
            // 1. 检查文件是否存在，存在则读取，若不存在则创建新列表

            if (file.exists()) {
                list = mapper.readValue(file, new TypeReference<List<DriverConfigDTO>>() {
                });
//                System.out.println(list);

                for (int i = 0; i < list.size(); i++) {
                    if (i == list.size() -1) {
                        System.out.println(1);
                    }

                    int address = Integer.valueOf(list.get(i).getAddress());

                    // 最后一次循环，添加数据到map中
                    if (i == list.size() - 1) {
                        Integer i1 = new Integer(startAddress);
                        Integer i2 = new Integer(length) +1;
                        selectMap.put(i1, i2);
                    }

                    // 获取json中的值
                    int numberOfWord = 0;
                    if (list.get(i).getBinaryCount().equals("16")) {
                        numberOfWord = 1;
                    } else if (list.get(i).getBinaryCount().equals("32")) {
                        numberOfWord = 2;
                        list32.add(address);
                    }
                    // 如果是第一次/重新计数
                    if (previousAddress == -1 && length == -1) {
                        startAddress = address;
                        previousAddress = address;
                        length = numberOfWord;
                        previousLength = numberOfWord;
                    }
                    // 如果是新的起始数据
                    else if (previousAddress == -1 && length != -1) {
                        // 如果上一个寄存器与当前寄存器都是16位或者32位寄存器
                        if (numberOfWord == previousLength) {
                            length += numberOfWord;
                            previousLength = numberOfWord;
                            previousAddress = address;
                        } else {
                            Integer i1 = new Integer(startAddress);
                            Integer i2 = new Integer(length);
                            selectMap.put(i1, i2);
                            length = numberOfWord;
                            startAddress = address;
                            previousAddress = -1;
                            previousLength = numberOfWord;
                        }
                    }
                    // 与上一个同时32位/16位寄存器，且连在一起
                    else if (address == previousAddress + previousLength && previousLength == numberOfWord) {

                        length += numberOfWord;
                        previousLength = numberOfWord;
                        previousAddress = address;

                    }
                    // 报文不在一起发
                    else {
                        Integer i1 = new Integer(startAddress);
                        Integer i2 = new Integer(length);
                        selectMap.put(i1, i2);
                        length = numberOfWord;
                        startAddress = address;
                        previousAddress = -1;
                        previousLength = numberOfWord;
                    }
                }
                log.info("配置文件加载完成：{}", selectMap);


                log.info("32位寄存器：{}", list32);
            } else {
                // 文件不存在，初始化一个新列表
                log.info("文件不存在");
            }
        } catch (IOException e) {
            throw new RuntimeException("未找到json文件");
        }
    }

    private List<DriverConfigDTO> handleData(){
        resultAllData = BaseSerialImpl.resultAllData;
        List returnList = new ArrayList();

        for (int i = 0; i < list.size(); i++) {
            DriverConfigDTO configDTO = list.get(i);
            int address = Integer.valueOf(configDTO.address);
            if (resultAllData.containsKey(address)){

                if (configDTO.type.equals("float")){
                    Long value = Long.valueOf((String) resultAllData.get(address));

                    // 将 Long 值转换为 Big-endian 的 4 字节数组
                    ByteBuffer bigEndianBuffer = ByteBuffer.allocate(8);  // Long 占用 8 字节
                    bigEndianBuffer.order(ByteOrder.BIG_ENDIAN);
                    bigEndianBuffer.putLong(value);
                    byte[] bigEndianBytes = bigEndianBuffer.array();

                    // 如果你只需要最后 4 字节（类似 Modbus 单个寄存器），则截取最后 4 个字节
                    byte[] lastFourBytes = Arrays.copyOfRange(bigEndianBytes, 4, 8);

                    // 你可以将字节数组转换为 Little-endian 或直接传输
                    ByteBuffer littleEndianBuffer = ByteBuffer.allocate(4);
                    littleEndianBuffer.order(ByteOrder.LITTLE_ENDIAN);
                    littleEndianBuffer.put(lastFourBytes);
                    littleEndianBuffer.flip();

                    // 转换为 float（如果确实需要存储浮点数格式）
                    float littleEndianFloat = littleEndianBuffer.getFloat();

                    // 更新 configDTO
                    configDTO.setValue(String.valueOf(littleEndianFloat));
                    returnList.add(configDTO);
                }else {
                    String value = resultAllData.get(address).toString();
                    configDTO.setValue(String.valueOf(value));
                    returnList.add(configDTO);
                }
            }else {
                configDTO.setValue(NO_DATA_AVAILABLE);
                //若map中无数据，则返回到前端直接展示无数据
                returnList.add(configDTO);
            }

        }
        return returnList;
    }
}
